#define print_zero_flag PSW.5


#if !defined(__SDCC_mcs51) || defined(__SDCC_USE_XSTACK) || defined(_SDCC_NO_ASM_LIB_FUNCS)
/* Does printf_tiny really work on ds390 and ds400?
   If it does, enable them in the line above */
#if defined(_SDCC_BUILD_LIB)
/* Disable all warnings if building a library */
#pragma disable_warning 190
#elif defined(__SDCC_USE_XSTACK)
#warning "printf_tiny not built, does not support --xstack"
#elif defined(_SDCC_NO_ASM_LIB_FUNCS)
#warning "printf_tiny not built, _SDCC_NO_ASM_LIB_FUNCS defined"
#else
/* Disable "ISO C forbids an empty source file" warning message */
#pragma disable_warning 190
#endif
#else /* defines are compatible with printf_tiny */



void printf_tiny( __code const char *fmt, ... ) __reentrant {
  fmt;	/* suppress unreferenced variable warning */

  __asm

  printf_begin:
  mov	a, _bp		/* r0 will point to va_args (stack) */
  add	a, #253
  mov	r0, a		/* r0 points to MSB of fmt */
  mov	dph, @r0
  dec	r0
  mov	dpl, @r0	/* dptr has address of fmt */
  dec	r0


  printf_main_loop:
  clr	a
  movc	a, @a+dptr	/* get next byte of fmt string */
  inc	dptr
  add	a, #256 - 37
  jz	printf_format	/* check for '%' */
  add	a, #37
  jz	printf_end_h
  lcall	printf_putchar
  sjmp	printf_main_loop
  printf_end_h:
  ljmp	printf_end


  printf_format:
  setb	print_zero_flag
  clr	a
  movc	a, @a+dptr	/* get next byte of data format */
  inc	dptr
  push	dph
  push	dpl


  printf_format_s:
  /*cjne	a, #'s', printf_format_c*/
  cjne	a, #115, printf_format_c
  printf_string:
  /* print a string... just grab each byte with __gptrget */
  /* the user much pass a 24 bit generic pointer */
  mov	b, @r0		/* b has type of address (generic *) */
  dec	r0
  mov	dph, @r0
  dec	r0
  mov	dpl, @r0	/* dptr has address of user's string */
  dec	r0
  printf_str_loop:
  lcall	__gptrget
  jz	printf_format_done
  inc	dptr
  lcall	printf_putchar
  sjmp	printf_str_loop


  printf_format_c:
  /*cjne	a, #'c', printf_format_d*/
  cjne	a, #99, printf_format_d
  dec	r0
  mov	a, @r0		/* Acc has the character to print */
  dec	r0
  lcall	printf_putchar
  sjmp	printf_format_done


  printf_format_d:
  /*cjne	a, #'d', printf_format_u*/
  cjne	a, #100, printf_format_x
  #ifndef ALWAYS_PRINT_UNSIGNED
  mov	a, @r0
  jnb	acc.7, printf_uint
  dec	r0
  mov	a, @r0
  cpl	a
  add	a, #1
  mov	@r0, a
  inc	r0
  mov	a, @r0
  cpl	a
  addc	a, #0
  mov	@r0, a
  /*mov	a, #'-'*/
  mov	a, #45
  lcall	printf_putchar
  #endif
  sjmp	printf_uint


  printf_format_x:
  /*cjne	a, #'x', printf_format_u*/
  cjne	a, #120, printf_format_u
  mov	dph, @r0
  dec	r0
  mov	dpl, @r0
  dec	r0
  clr	a
  printf_hex:
  lcall	printf_phex_lsn
  mov	a, dph
  lcall	printf_phex_msn
  mov	a, dph
  lcall	printf_phex_lsn
  mov	a, dpl
  lcall	printf_phex_msn
  mov	a, dpl
  lcall	printf_phex_lsn
  jnb	print_zero_flag, printf_format_done
  /*mov	a, #'0'*/
  mov	a, #48
  lcall	printf_putchar
  printf_format_done:
  pop	dpl
  pop	dph
  ljmp	printf_main_loop


  printf_format_u:
  /*cjne	a, #'u', printf_format_done*/
  cjne	a, #117, printf_format_done
  printf_uint:
  mov	a, @r0
  mov	r2, a
  dec	r0
  mov	a, @r0
  mov	r1, a
  dec	r0
  printf_int2bcd:
  mov	r4, #16
  mov	r5, #39
  lcall	div_by_sub
  mov	r7, a
  mov	r4, #232
  mov	r5, #3
  lcall	div_by_sub
  swap	a
  mov	dph, a
  mov	r4, #100
  mov	r5, #0
  lcall	div_by_sub
  orl	dph, a
  mov	a, r1
  mov	b, #10
  div	ab
  swap	a
  orl	a, b
  mov	dpl, a
  mov	a, r7
  sjmp	printf_hex


  /* Divide r2/r1 by r5/r4 using successive subtraction
     returns quotient in r2/r1 and remainder in acc. */
  div_by_sub:
  mov     r3, #0
  div_by_sub_loop:
  inc     r3
  clr     c
  mov     a, r1
  subb    a, r4
  mov     r1, a
  mov     a, r2
  subb    a, r5
  mov     r2, a
  jnc     div_by_sub_loop
  dec     r3
  mov     a, r1
  add     a, r4
  mov     r1, a
  mov     a, r2
  addc    a, r5
  mov     r2, a
  mov     a, r3
  ret


  /* print a hex digit, either upper 4 bit (msn) or lower 4 bits (lsn) */
  printf_phex_msn:
  swap	a
  printf_phex_lsn:
  anl	a, #15
  jnz	printf_phex_ok
  jb	print_zero_flag, printf_ret
  printf_phex_ok:
  clr	print_zero_flag
  add	a, #0x90
  da	a
  addc    a, #0x40
  da	a
  printf_putchar:
  #ifdef DIRECT_SERIAL_OUTPUT
  jnb	ti, printf_putchar
  clr	ti
  mov	sbuf, a
  #else
  push	dph
  push	dpl
  push	b
  mov	dpl, a
  mov	a, r0
  push	acc
  lcall	_putchar
  pop	acc
  mov	r0, a
  pop	b
  pop	dpl
  pop	dph
  #endif
  printf_ret:
  ret


  printf_end:
  __endasm;
}


#endif /* defines compatible with printf_tiny */
